iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 27
1

本篇同步發文在個人Blog: 一袋.NET要扛幾樓?打造容器化的ASP.NET Core網站!系列文章 - (27) 建立購物車系統 - 10

1. 在WebMvc專案新增購物車服務的功能

1.1 修改appSettings.json

在WebMvc專案的appSettings.json增加購物車服務的Api連結:

  "CartUrl": "http://localhost:1028",

1.2 修改Startup.cs類別

修改WebMvc專案的Startup.cs,主要是增加在OIDC的購物車Scope、註冊購物車相關服務:

    using Microsoft.AspNetCore.Authentication.Cookies;
    using Microsoft.AspNetCore.Authentication.OpenIdConnect;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Newtonsoft.Json.Serialization;
    using System.IdentityModel.Tokens.Jwt;
    using System.Net.Http;
    using WebMvc.Infrastructure;
    using WebMvc.Models;
    using WebMvc.Services;
    
    namespace WebMvc
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.Configure<AppSettings>(Configuration);
                services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
                services.AddSingleton<IHttpClient, CustomHttpClient>();
                services.AddTransient<ICatalogService, CatalogService>();
    
                services.AddTransient<IAuthService<ApplicationUser>, AuthService>();
                services.AddTransient<ICartService, CartService>();
    
                services.AddControllersWithViews().AddNewtonsoftJson(options =>
                {
                    options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
                });
    
                JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
    
                var identityUrl = Configuration.GetValue<string>("IdentityUrl");
                var callBackUrl = Configuration.GetValue<string>("CallBackUrl");
                services.AddAuthentication(options =>
                {
                    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                })
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
                {
                    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.Authority = identityUrl;
                    options.SignedOutRedirectUri = callBackUrl;
                    options.ClientId = "mvc";
                    options.ClientSecret = "secret";
                    options.ResponseType = "code id_token";
                    options.SaveTokens = true;
                    options.GetClaimsFromUserInfoEndpoint = true;
                    options.RequireHttpsMetadata = false;
                    options.Scope.Add("openid");
                    options.Scope.Add("profile");
                    options.Scope.Add("offline_access");
                    options.Scope.Add("basket");
    
                    options.NonceCookie.SameSite = SameSiteMode.Lax;
                    options.CorrelationCookie.SameSite = SameSiteMode.Lax;
    
                    options.BackchannelHttpHandler = new HttpClientHandler()
                    {
                        ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
                    };
                });
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                }
                app.UseStaticFiles();
    
                app.UseRouting();
    
                app.UseAuthentication();
                app.UseAuthorization();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "{controller=Catalog}/{action=Index}/{id?}");
                });
            }
        }
    }

===

1.3 新增Cart和CartList的ViewComponent

在WebMvc專案新增ViewComponents資料夾,並新增Cart.cs和CartList.cs 2個類別,都實作Microsoft.AspNetCore.Mvc.ViewComponent,之後Views的cshtml可以直接把它們當function呼叫並產生子View:

    using Microsoft.AspNetCore.Mvc;
    using System;
    using System.Threading.Tasks;
    using WebMvc.Models;
    using WebMvc.Services;
    using WebMvc.ViewModels;
    
    namespace WebMvc.ViewComponents
    {
        public class Cart : ViewComponent
        {
            private readonly ICartService _cartService;
            public Cart(ICartService cartService)
            {
                _cartService = cartService;
            }
    
            public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user)
            {
                var vm = new CartComponentViewModel();
                try
                {
                    var cart = await _cartService.GetCartAsync(user);
                    vm.ItemsInCart = cart.Items.Count;
                    vm.TotalCost = cart.Total();
                    return View(vm);
                }
                catch (Exception)
                {
                    ViewBag.IsCartInoperative = true;
                }
    
                return View(vm);
            }
        }
    }
    using Microsoft.AspNetCore.Mvc;
    using System;
    using System.Threading.Tasks;
    using WebMvc.Models;
    using WebMvc.Services;
    
    namespace WebMvc.ViewComponents
    {
        public class CartList : ViewComponent
        {
            private readonly ICartService _cartService;
            public CartList(ICartService cartService)
            {
                _cartService = cartService;
            }
    
            public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user)
            {
                var vm = new Models.CartModels.Cart();
                try
                {
                    vm = await _cartService.GetCartAsync(user);
                    return View(vm);
                }
                catch (Exception)
                {
                    ViewBag.IsCartInoperative = true;
                    TempData["CartInoperativeMsg"] = "Cart Service is inoperative, please retry later.";
                }
    
                return View(vm);
            }
        }
    }

1.4 新增CartComponentViewModel類別

在WebMvc專案的ViewModels新增CartComponentViewModel.cs,是Cart ViewComponent要回傳的View:

    namespace WebMvc.ViewModels
    {
        public class CartComponentViewModel
        {
            public int ItemsInCart { get; set; }
            public decimal TotalCost { get; set; }
            public string Disabled => (ItemsInCart == 0) ? "is-disabled" : "";
        }
    }

上一篇
[Day26] 建立購物車系統 - 9
下一篇
[Day28] 建立購物車系統 - 11
系列文
一袋.NET要扛幾樓?打造容器化的ASP.NET Core網站!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言